package trigger

import (
	"bgs/db"
	sqlc "bgs/db/sqlc"
	nsqModel "bgs/nsqp/model"
	nsqpUtil "bgs/nsqp/util"
	ledgerService "bgs/service/ledger"
	orderService "bgs/service/order"
	"bgs/util"
	"bytes"
	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"github.com/nsqio/go-nsq"
	"go.uber.org/zap"
	"strconv"
)

// SubmitOrderProfitShareAtAfterSaleDeadlineHandler 售后截止时提交订单分账 handler
type SubmitOrderProfitShareAtAfterSaleDeadlineHandler struct {
	dao           *db.PgDao
	slog          *zap.SugaredLogger
	topic         string
	failover      *nsqpUtil.NsqFailover
	ledgerService *ledgerService.LedgerServiceImp
	orderService  *orderService.OrderServiceImp
}

// NewSubmitOrderProfitShareAtAfterSaleDeadlineHandler create a new handler for SubmitOrderProfitShareAtAfterSaleDeadlineHandler
func NewSubmitOrderProfitShareAtAfterSaleDeadlineHandler(
	pgdao *db.PgDao,
	slog *zap.SugaredLogger,
	topic string,
	failover *nsqpUtil.NsqFailover,
	ledgerService *ledgerService.LedgerServiceImp,
	orderService *orderService.OrderServiceImp,
) *SubmitOrderProfitShareAtAfterSaleDeadlineHandler {
	return &SubmitOrderProfitShareAtAfterSaleDeadlineHandler{
		dao:           pgdao,
		slog:          slog.With("module", "SubmitOrderProfitShareAtAfterSaleDeadlineHandler"),
		topic:         topic,
		failover:      failover,
		ledgerService: ledgerService,
		orderService:  orderService,
	}
}

// HandleMessage implements the Handler interface.
func (h *SubmitOrderProfitShareAtAfterSaleDeadlineHandler) HandleMessage(m *nsq.Message) error {
	if len(m.Body) == 0 {
		// Returning nil will automatically send a FIN command to NSQ to mark the message as processed.
		return nil
	}

	h.slog.Infof("SubmitOrderProfitShareAtAfterSaleDeadlineMessage=>%s", string(m.Body))

	v := &nsqModel.CronMomentMessage{}
	if decodeErr := json.NewDecoder(bytes.NewReader(m.Body)).Decode(v); decodeErr != nil {
		return fmt.Errorf("无法解析信息[SubmitOrderProfitShareAtAfterSaleDeadlineMessage]: %v", decodeErr)
	}

	reqID := strconv.FormatInt(v.TS, 10)
	ctx := context.WithValue(context.Background(), util.RequestID{}, reqID)

	var err error
	defer h.failover.BackupSubMsgWhenHandleFail(ctx, &err, nsqpUtil.BackupSubMsgParam{
		Ts:    v.TS,
		Topic: h.topic,
		Mbody: m.Body,
	})

	err = h.dao.NewTxRunner().SqlcExecTx(ctx, func(q *sqlc.Queries) (err error) {
		limit := util.Int32IfThenElse(v.Data.Limit > 0, v.Data.Limit, 5)
		orders, err := q.ListOrdersOfUnProfitedAtAfterSaleExpired(ctx, limit)
		if err != nil {
			return
		}
		count := len(orders)
		if count > 0 {
			for i := range orders {
				// 查看订单对应的分账明细中是否有售后结束时需要分账(解冻)的记录,如果有,则提交wxpay分账
				orderPtr := &orders[i]
				orderSerialNumber := orderPtr.SerialNumber
				h.slog.Infof("a SubmitOrderProfitShareAtAfterSaleDeadline-处理订单(%s)-(%s) ok", orderSerialNumber, sqlc.EmProfitTriggerAtAfterSaleDeadline)
				ledgerRequest, sqlErr := q.GetLedgerRequestByOrderSerialNumberAndProfitTrigger(ctx, sqlc.GetLedgerRequestByOrderSerialNumberAndProfitTriggerParams{
					OrderSerialNumber: orderSerialNumber,
					ProfitTrigger:     string(sqlc.EmProfitTriggerAtAfterSaleDeadline),
				})
				if sqlErr != nil {
					if sql.ErrNoRows == sqlErr {
						h.slog.Infof("SubmitOrderProfitShareAtAfterSaleDeadline-在订单售后完成完成场景没有找到分账申请,无须提交分账")
						continue
					} else {
						// h.slog.Infof("订单(%s)获取分账请求(RequestToProxyAtAfterSaleDeadline)失败:%s", orderSerialNumber, err.Error())
						err = fmt.Errorf("订单(%s)获取分账请求失败:%s", orderSerialNumber, sqlErr.Error())
					}
				} else {
					// 没有错误
					h.slog.Infof("SubmitOrderProfitShareAtAfterSaleDeadline-获取在订单售后完成场景的分账请求信息(%s)成功", ledgerRequest.SerialNumber)
					err = h.ledgerService.RequestToProxy(ctx, q, &ledgerRequest)
					if err != nil {
						err = fmt.Errorf("分账请求(%s)请求分账失败:%s", ledgerRequest.SerialNumber, err.Error())
					}
				}
			}
		}
		h.slog.Infof("a SubmitOrderProfitShareAtAfterSaleDeadline-处理分账订单(%d条) ok", count)
		return
	})

	if err != nil {
		h.slog.Infof("SubmitOrderProfitShareAtAfterSaleDeadline-分账场景(RequestToProxyAtAfterSaleDeadline)发生错误(%s), 因为周期性不处理仅打印", err.Error())
		err = nil
	}
	// Returning a non-nil error will automatically send a REQ command to NSQ to re-queue the message.
	return nil
}
